package com.oweight.com2tpc.connect.tcp;

import cn.hutool.core.io.BufferUtil;
import cn.hutool.core.lang.Console;
import cn.hutool.core.util.HexUtil;
import com.oweight.com2tpc.Controller;
import com.oweight.com2tpc.connect.Constant;
import com.oweight.com2tpc.connect.serial.SerialClient;
import io.netty.channel.Channel;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
import io.netty.util.concurrent.ScheduledFuture;
import lombok.extern.slf4j.Slf4j;

import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeUnit;

@Slf4j
public class TCPDataHandler extends ChannelDuplexHandler {
	private final Controller controller;

	public TCPDataHandler(Controller controller1) {
		this.controller = controller1;
	}

	@Override
	public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
		super.write(ctx, msg, promise);
		controller.setTcpDataDown();
	}

	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
		super.channelRead(ctx, msg);
		try {
			controller.setTcpDataUp();
			SerialClient.channel.writeAndFlush(msg);
		} catch (Exception ignored) {
		}
	}

	@Override
	public void channelActive(ChannelHandlerContext ctx) throws Exception {
		super.channelActive(ctx);
		Console.log("TCP/IP连接成功！");
		ping(ctx.channel());
		if (SerialClient.channel != null) {
			ctx.channel().writeAndFlush(Constant.COM_OPEN.getBytes());
			SerialClient.channel.writeAndFlush(Constant.TPC_OPEN.getBytes());
		} else {
			ctx.channel().writeAndFlush(Constant.COM_CLOSED.getBytes());
		}

	}

	@Override
	public void channelInactive(ChannelHandlerContext ctx) throws Exception {
		super.channelInactive(ctx);
		Console.log("TCP/IP断开连接！");
		if (SerialClient.channel != null) {
			SerialClient.channel.writeAndFlush(Constant.TPC_CLOSED.getBytes());
		}
		TCPClient.channel = null;
	}
	private void ping(Channel channel) {
		int second = 1;
		System.out.println("next heart beat will send after " + second + "s.");
		ScheduledFuture<?> future = channel.eventLoop().schedule(new Runnable() {
			@Override
			public void run() {
				if (channel.isActive()) {
					channel.writeAndFlush(Constant.PING.getBytes(StandardCharsets.UTF_8));
				} else {
					System.err.println("The connection had broken, cancel the task that will send a heart beat.");
					channel.closeFuture();
					throw new RuntimeException();
				}
			}
		}, second, TimeUnit.SECONDS);
		future.addListener(new GenericFutureListener() {
			@Override
			public void operationComplete(Future future) throws Exception {
				if (future.isSuccess()) {
					ping(channel);
				}
			}
		});
	}
}
